import { defineComponent, ref, onMounted, watch, onBeforeUnmount } from 'vue';
import { cn } from '@/lib/utils';

interface NumberTickerProps {
  value: number;
  direction?: 'up' | 'down';
  className?: string;
  delay?: number; // delay in seconds
  decimalPlaces?: number;
}

const NumberTicker = defineComponent({
  name: 'NumberTicker',
  props: {
    value: {
      type: Number,
      required: true,
    },
    direction: {
      type: String,
      default: 'up',
    },
    className: {
      type: String,
      default: '',
    },
    delay: {
      type: Number,
      default: 0,
    },
    decimalPlaces: {
      type: Number,
      default: 0,
    },
  },
  setup(props: NumberTickerProps) {
    const refElement = ref<HTMLElement | null>(null);
    const displayedValue = ref(props.direction === 'down' ? 0 : props.value);

    const observer = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          setTimeout(() => {
            animateValue(displayedValue.value, props.value, props.direction);
          }, props.delay * 1000);
          observer.unobserve(entry.target); // Stop observing after the first intersection
        }
      });
    });

    const animateValue = (start: number, end: number, direction: 'up' | 'down') => {
      const duration = 1000; // 动画持续时间
      const startTime = performance.now();

      const step = (currentTime: number) => {
        const elapsed = currentTime - startTime;
        const progress = Math.min(elapsed / duration, 1);
        const value = direction === 'up'
          ? Math.floor(start + (end - start) * progress)
          : Math.floor(end + (start - end) * progress);

        displayedValue.value = value;

        if (progress < 1) {
          requestAnimationFrame(step);
        } else {
          displayedValue.value = end; // 确保最终值设置为目标值
        }
      };

      requestAnimationFrame(step);
    };

    onMounted(() => {
      if (refElement.value) {
        observer.observe(refElement.value);
      }
    });

    onBeforeUnmount(() => {
      if (refElement.value) {
        observer.unobserve(refElement.value);
      }
    });

    watch(() => props.value, (newValue) => {
      animateValue(displayedValue.value, newValue, props.direction);
    });

    return () => (
      <span
        class={cn(
          'inline-block tabular-nums text-black dark:text-white tracking-wider',
          props.className,
        )}
        ref={refElement}
      >
        {Intl.NumberFormat('en-US', {
          minimumFractionDigits: props.decimalPlaces,
          maximumFractionDigits: props.decimalPlaces,
        }).format(displayedValue.value)}
      </span>
    );
  },
});

export default NumberTicker;